#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <functional>
#include <mutex>
#include <thread>
#include <condition_variable>
#include <atomic>
#include <future>
using namespace std;

using task_t = function<void(void)>;
const int default_thread_num = 1;
class threadpool {
public :
    threadpool(int thread_num = default_thread_num) 
        :_stop(false)
    {
        // 创建指定数量的线程
        for (int i = 0; i < thread_num; i++) {
            _threads.emplace_back(&threadpool::entry, this); // 原地构造

        }
    }
    template<typename F, typename ...Args>
    auto push(F &&func, Args&& ...args) -> future<decltype(func(args...))> {
        // 1、将闯入的函数封装成一个packaged_task任务
        using return_type = decltype(func(args...)); // 类型自动推导
        auto temp_func = bind(forward<F>(func), forward<Args>(args)...); // 将参数绑定
        auto task = std::make_shared<packaged_task<return_type()>>(temp_func);
        future<return_type> fu = task->get_future();
        {
            unique_lock<mutex> lock(_mtx);
            _tasks.push_back([task](){ (*task)(); });
        }
        _cond.notify_all();
        return fu;
    }

    void stop() {
        {
            unique_lock<mutex> lock(_mtx);
            if (_stop == true) {
                return;
            }
        }

        _stop = true;
        // 唤醒所有线程
        _cond.notify_all();
        for (auto& t : _threads) {
            t.join();
        }
    }
    ~threadpool() {
        stop();
    }
private :
    void entry() {
        while (!_stop) {
            vector<task_t> temp_tasks;
            {
                unique_lock<mutex> lock(_mtx);
                // 等待任务池不为空，或者_stop被置位返回
                _cond.wait(lock, [this]() {
                    return !_stop || !_tasks.empty();
                });
                // 取出任务并执行
                temp_tasks.swap(_tasks);
            }
            for (auto& task : temp_tasks) {
                task();
            }
        }

    }

private :
    vector<task_t> _tasks; // 任务池
    mutex _mtx; // 互斥锁
    condition_variable _cond; // 条件变量
    vector<thread> _threads; // 一批工作线程(条件变量和互斥锁一定要定义在线程前面)
    atomic<bool> _stop; // 标记线城市是否退出
};


